#include "item/ellipseitem.h"

#include <QtMath>
#include <QStyleOptionGraphicsItem>
#include <QPainter>

namespace SymbolEditor
{

    GraphicsEllipseItem::GraphicsEllipseItem(GraphicsItem *parent):
        GraphicsItem(parent),
        m_xRadius(0.0f), m_yRadius(0.0f)
    {
        addHandle(XRadiusHandle, Handle::Role::Move, Handle::Shape::Diamond);
        addHandle(YRadiusHandle, Handle::Role::Move, Handle::Shape::Diamond);
    }

    GraphicsEllipseItem::~GraphicsEllipseItem()
    {

    }

    qreal GraphicsEllipseItem::xRadius() const
    {
        return m_xRadius;
    }

    qreal GraphicsEllipseItem::yRadius() const
    {
        return m_yRadius;
    }

    void GraphicsEllipseItem::setXRadius(qreal xRadius)
    {
        if (qFuzzyCompare(m_xRadius, xRadius))
        {
            return;
        }

        prepareGeometryChange();
        m_xRadius = xRadius;
        m_boundingRect = QRectF();
        update();

        blockItemNotification();
        m_idToHandle[XRadiusHandle]->setPos(m_xRadius, 0);
        unblockItemNotification();
    }

    void GraphicsEllipseItem::setYRadius(qreal yRadius)
    {
        if (qFuzzyCompare(m_yRadius, yRadius))
        {
            return;
        }

        prepareGeometryChange();
        m_yRadius = yRadius;
        m_boundingRect = QRectF();
        update();

        blockItemNotification();
        m_idToHandle[YRadiusHandle]->setPos(0, m_yRadius);
        unblockItemNotification();
    }

    QPointF GraphicsEllipseItem::pointAt(qreal angle) const
    {
        qreal theta = qDegreesToRadians(angle);
        return QPointF(m_xRadius * qCos(theta), -m_yRadius * qSin(theta));
    }

    qreal GraphicsEllipseItem::angleAt(const QPointF &pos) const
    {
        QLineF vector(QPointF(0, 0), QPointF(pos.x() / xRadius(), pos.y() / m_yRadius));
        return vector.angle();
    }

    QRectF GraphicsEllipseItem::boundingRect() const
    {
        if (m_boundingRect.isNull())
        {
            qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
            if (pw == 0.0 /*&& m_spanAngle == 360 * 16*/)
            {
                m_boundingRect.setWidth(2 * xRadius());
                m_boundingRect.setHeight(2 * yRadius());
            }
            else
            {
                m_boundingRect = shape().controlPointRect();
            }
        }
        return m_boundingRect;
    }

    QPainterPath GraphicsEllipseItem::shape() const
    {
        QPainterPath path;
        path.addEllipse(QPointF(0, 0), m_xRadius, m_yRadius);
        return shapeFromPath(path, pen());
    }

    void GraphicsEllipseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
                            QWidget *widget)
    {
        Q_UNUSED(widget);

        painter->setPen(pen());
        painter->setBrush(brush());
        painter->setClipRect(option->exposedRect);
        painter->drawEllipse(QPointF(0, 0), xRadius(), yRadius());
    }

    GraphicsItem *GraphicsEllipseItem::clone()
    {
        GraphicsEllipseItem *item = new GraphicsEllipseItem();
        item->setXRadius(xRadius());
        item->setYRadius(yRadius());
        GraphicsItem::cloneTo(item);
        return item;
    }

    QList<PropertyId> GraphicsEllipseItem::propertyIdList() const
    {
        return GraphicsItem::propertyIdList() << XRadiusProperty
                                              << YRadiusProperty;
    }

    void GraphicsEllipseItem::setProperty(PropertyId id, const QVariant &value)
    {
        switch (id)
        {
            case XRadiusProperty:
                setXRadius(value.toReal());
                break;
            case YRadiusProperty:
                setYRadius(value.toReal());
                break;
            default:
                GraphicsItem::setProperty(id, value);
                break;
        }
    }

    QVariant GraphicsEllipseItem::property(PropertyId id) const
    {
        switch (id)
        {
            case XRadiusProperty:
                return xRadius();
            case YRadiusProperty:
                return yRadius();
            default:
                return GraphicsItem::property(id);
        }
    }

    QList<QPointF> GraphicsEllipseItem::endPoints() const
    {
        return QList<QPointF>() << QPointF(m_xRadius, 0);
    }

    QList<QPointF> GraphicsEllipseItem::midPoints() const
    {
        return QList<QPointF>();
    }

    QList<QPointF> GraphicsEllipseItem::centerPoints() const
    {
        return QList<QPointF>() << QPointF(0, 0);
    }

    QList<QPointF> GraphicsEllipseItem::nearestPoints(QPointF pos) const
    {
        qreal theta = angleAt(mapFromScene(pos));
        return QList<QPointF>() << pointAt(theta);
    }

    QVariant GraphicsEllipseItem::itemChange(QGraphicsItem::GraphicsItemChange change,
                                     const QVariant &value)
    {
        if (change == QGraphicsItem::ItemSelectedHasChanged)
        {
            for (Handle *handle : m_handleToId.keys())
            {
                handle->setVisible(isSelected());
            }
        }
        return value;
    }

    void GraphicsEllipseItem::itemNotification(IObservableItem *item)
    {
        Handle *handle = static_cast<Handle *>(item);
        if (handle == m_idToHandle[XRadiusHandle])
        {
            setXRadius(qAbs(handle->pos().x()));
        }
        else
        {
            setYRadius(qAbs(handle->pos().y()));
        }
    }

}
